using UnityEngine;
using System.Collections;

public class CameraController : MonoBehaviour {
	public Camera _camera;
	
	private static CameraController instance;
	public static CameraController GetInstance()
	{
		return instance;
	}
	
	public enum CameraDirection{
		NorthEast = 0,
		SouthEast = 1,
		SouthWest = 2,
		NorthWest = 3
	};
	
	public GameObject target;
	public bool isFollow = false;
	public CameraDirection _camDirection = CameraDirection.SouthWest;
	public float respondDelayFactor = 0.5f;
	public Vector3 defalutCameraOffset = new Vector3(10,10,10);
	
	public bool isShaking = true;
	public Vector3 defaultShaking = new Vector3(0.1f,0.1f,0.1f);
	
	[HideInInspector]
	public Vector3 shaking;
	[HideInInspector]
	public Vector3 cameraOffset;
	
	private Vector3 desireCameraPos;
	
	private bool isBlocked;
	private Vector3 blockPos;
	
	private Volume blockedVolume;
	// Use this for initialization
	void Start () {
		instance = this;
		cameraOffset = defalutCameraOffset;
		shaking = GetRandomShaking();
		//camera.isOrthoGraphic = true;
		//camera.orthographicSize = 9;
	}
	
	public Vector3 GetRandomShaking()
	{
		Vector3 temp = new Vector3(Random.Range(0,defaultShaking.x),Random.Range(0,defaultShaking.y),Random.Range(0,defaultShaking.z));
		return temp;
	}
	public void resetCameraOffset()
	{
		cameraOffset = defalutCameraOffset;
	}
	public CameraDirection camDirection
	{
		get{return _camDirection;}
		set{
			cameraOffset.x = Mathf.Abs(cameraOffset.x);
			cameraOffset.z = Mathf.Abs(cameraOffset.x); // x = z
			
			switch(value)
			{
				case CameraDirection.NorthEast:
					
					break;
				case CameraDirection.SouthEast:
					cameraOffset.z = -cameraOffset.z;
					break;
				case CameraDirection.SouthWest:
					cameraOffset.x = -cameraOffset.x;
					cameraOffset.z = -cameraOffset.z;
					break;
				case CameraDirection.NorthWest:
					cameraOffset.x = -cameraOffset.x;
					break;
			}
			_camDirection = value;
		}
	}
	public void RotateLeft()
	{
		camDirection = (CameraDirection)(((int)camDirection + 1) % 4);
	}
	public void RotateRight()
	{
		int temp = (int)camDirection - 1;
		camDirection = (CameraDirection)(temp >= 0 ? temp : 3);
	}    

	void OnTriggerEnter(Collider collider)
	{
		//print("OnTriggerEnter");
		
		Volume v = collider.gameObject.GetComponent<Volume>();
		
		if(v && v.type == VolumeType.VTCamera)
		{
			OnCameraEnterBlock(v);
		}
	}
	void OnTriggerStay(Collider collider)
	{
		//print("OnTriggerStay");
		Volume v = collider.gameObject.GetComponent<Volume>();
		if(v && v.type == VolumeType.VTCamera)
		{
			float distFromPlayerToCam = Vector3.Distance(camera.transform.position,target.transform.position);
			if(distFromPlayerToCam > defalutCameraOffset.magnitude)
			{
				resetCameraOffset();
				blockedVolume = null;
			}else
			{
				OnCameraEnterBlock(v);
			}
		}
	}
	void OnTriggerExit()
	{
		blockedVolume = null;
	}
	void OnCameraEnterBlock(Volume v)
	{
		Ray ray = new Ray(target.transform.position, _camera.transform.position - target.transform.position);
		blockedVolume = v;
		
		//calcuate the closest distance from player to blocking sth.
		float d = 0;
		if(blockedVolume.volume.bounds.IntersectRay(ray,out d))
		{
			blockPos = ray.origin+ray.direction*d;
				
		}
		
		//print("OnCameraEnterBlock");
	}
	void OnDrawGizmos()
	{
		Ray ray = new Ray(target.transform.position, _camera.transform.position - target.transform.position);
		
		Gizmos.DrawLine(ray.origin,_camera.transform.position);
		if(blockedVolume)
		{
			//Gizmos.DrawWireCube(blockedVolume.volume.bounds.center,blockedVolume.volume.bounds.size);
			//Gizmos.DrawSphere(blockPos,0.2f);
			
		}
	}
	void Update () {
		
		if(target == null)
		{
			print("Camera target is null");
			return;
		}
		Vector3 lookAtPos = target.transform.position + target.transform.up * cameraOffset.z;
		Vector3 relativePos = lookAtPos  - _camera.transform.position;
    	//Quaternion rotation = Quaternion.LookRotation(relativePos);
    	//camera.transform.rotation = rotation;
    	
		Vector3 newCameraPos = _camera.transform.position;
    	if(isFollow)
    	{
    		//if target is far from the camera
			if(blockedVolume != null)
			{
				desireCameraPos = blockPos;
				
			}
    		else if(relativePos.magnitude > 4)
    		{
    			//move closer
    			desireCameraPos = target.transform.position + 
    							(target.transform.forward * cameraOffset.x) + 
    							(target.transform.up * cameraOffset.y) ;
    			
    		}
			
			newCameraPos = UtilEx.cLerp(newCameraPos,desireCameraPos,target.transform.position,Time.deltaTime);
			//newCameraPos = Vector3.Lerp(newCameraPos,desireCameraPos,Time.deltaTime* respondDelayFactor);
			
    	}else
		{
			desireCameraPos = target.transform.position + cameraOffset;
			newCameraPos = Vector3.Lerp(newCameraPos,desireCameraPos,Time.deltaTime * respondDelayFactor);
			
			
		}
		
		
		
		
		
		_camera.transform.position = newCameraPos;
		_camera.transform.LookAt(target.transform);
    	
	}
}
